package com.disapand.strongarmy.service.impl

import cn.dev33.satoken.stp.*
import com.disapand.strongarmy.model.*
import com.disapand.strongarmy.service.*
import com.disapand.strongarmy.vo.*
import com.disapand.strongarmy.vo.role.*
import org.ktorm.database.*
import org.ktorm.dsl.*
import org.ktorm.entity.*
import org.springframework.stereotype.*
import java.time.*
import kotlin.math.*

/**
 *
 * @auth disapand
 * @date 2021/10/19 - 21:45 - 星期二
 *
 */
@Service
class RoleServiceImpl(
    private val database: Database
) : RoleService {

    /**
     * 添加角色
     *
     * @param label
     * @param role
     * @return
     */
    override fun add(label: String, role: String): Boolean {
        val userId = StpUtil.getLoginIdAsInt()

        val entity = Role {
            this.label = label
            this.role = role
            this.createdBy = userId
            this.createdAt = LocalDateTime.now()
        }

        val nums = database.roles.add(entity)
        return nums > 0
    }

    /**
     * 编辑角色信息
     *
     * @param id
     * @param label
     * @param role
     * @return
     */
    override fun edit(id: Int, label: String, role: String): Boolean {
        val roleEntity = get(id) ?: return false
        roleEntity.label = label
        roleEntity.role = role
        roleEntity.updatedAt = LocalDateTime.now()
        roleEntity.updatedBy = StpUtil.getLoginIdAsInt()
        return roleEntity.flushChanges() > 0
    }

    /**
     * 根据 id 查找角色
     *
     * @param id
     * @return
     */
    override fun get(id: Int): Role? {
        return database.roles.find { it.id eq id and (it.deleted eq false) }
    }

    /**
     * 根据角色名查找角色
     *
     * @param label
     * @return
     */
    override fun get(label: String): List<Role> {
        return database.roles
            .filter { it.label like "%$label%" }
            .filter { it.deleted eq false }
            .toList()
    }

    /**
     * 根据查询条件分页返回角色列表
     *
     * @param label
     * @param role
     * @param status
     * @param createdBy
     * @param createdAt
     * @param createdStartAt
     * @param createdEndAt
     * @param updatedBy
     * @param updatedAt
     * @param updatedStartAt
     * @param updatedEndAt
     * @param current
     * @param pageSize
     * @return
     */
    override fun page(
        label: String?,
        role: String?,
        status: List<Int>?,
        createdBy: Int?,
        createdAt: String?,
        createdStartAt: LocalDateTime?,
        createdEndAt: LocalDateTime?,
        updatedBy: Int?,
        updatedAt: String?,
        updatedStartAt: LocalDateTime?,
        updatedEndAt: LocalDateTime?,
        current: Int,
        pageSize: Int
    ): PageVO<RolePageVO> {
        val createdAccount = Accounts.aliased("created")
        val updatedAccount = Accounts.aliased("updated")

        val query = database.from(Roles)
            .leftJoin(createdAccount, on = Roles.createdBy eq createdAccount.id)
            .leftJoin(updatedAccount, on = Roles.updatedBy eq updatedAccount.id)
            .select(Roles.columns - Roles.deleted + createdAccount.username + updatedAccount.username)
            .whereWithConditions {
                if (label != null) it += Roles.label like "%${label}%"
                if (role != null) it += Roles.role like "%${role}%"
                if (status != null) it += Roles.status inList status
                if (createdBy != null) it += Roles.createdBy eq createdBy
                if (createdStartAt != null && createdEndAt != null)
                    it += Roles.createdAt between createdStartAt..createdEndAt
                if (createdStartAt != null && createdEndAt == null)
                    it += Roles.createdAt greaterEq createdStartAt
                if (createdStartAt == null && createdEndAt != null)
                    it += Roles.createdAt lessEq createdEndAt
                if (updatedBy != null) it += Roles.updatedBy eq updatedBy
                if (updatedStartAt != null && updatedEndAt != null)
                    it += Roles.updatedAt between updatedStartAt..updatedEndAt
                if (updatedStartAt != null && updatedEndAt == null)
                    it += Roles.updatedAt greaterEq updatedStartAt
                if (updatedStartAt == null && updatedEndAt != null)
                    it += Roles.updatedAt lessEq updatedEndAt
                it += Roles.deleted eq false
            }
            .orderBy(
                when {
                    createdAt != null && createdAt == "ascend" -> Roles.createdAt.asc()
                    createdAt != null && createdAt == "descend" -> Roles.createdAt.desc()
                    updatedAt != null && updatedAt == "ascend" -> Roles.updatedAt.asc()
                    updatedAt != null && updatedAt == "descend" -> Roles.updatedAt.desc()
                    else -> Roles.id.asc()
                }
            )
            .limit(pageSize * (current - 1), pageSize)

        val total = query.totalRecords
        val list = query.map { row ->
            RolePageVO(
                id = row[Roles.id],
                label = row[Roles.label],
                role = row[Roles.role],
                status = row[Roles.status],
                createdBy = row[Roles.createdBy],
                createdByName = row[createdAccount.username],
                createdAt = row[Roles.createdAt],
                updatedBy = row[Roles.updatedBy],
                updatedByName = row[updatedAccount.username],
                updatedAt = row[Roles.updatedAt]
            )
        }

        return PageVO(
            total = total,
            totalPage = ceil(total.toDouble() / pageSize).toInt(),
            current = current,
            pageSize = pageSize,
            list = list
        )
    }

    /**
     * 删除角色
     *
     * @param id
     * @return
     */
    override fun delete(id: List<Int>): Boolean {
        database.batchUpdate(Roles) {
            item {
                set(it.deleted, true)
                set(it.updatedAt, LocalDateTime.now())
                set(it.updatedBy, StpUtil.getLoginIdAsInt())
                where {
                    it.id inList id
                }
            }
        }
        return true
    }

    /**
     * 改变角色状态
     *
     * @param id
     * @param status 默认为禁用（0）
     * @return
     */
    override fun flushStatus(id: List<Int>, status: Int): Boolean {
        database.batchUpdate(Roles) {
            item {
                set(it.status, status)
                set(it.updatedAt, LocalDateTime.now())
                set(it.updatedBy, StpUtil.getLoginIdAsInt())
                where {
                    it.id inList id
                }
            }
        }
        return true
    }

    /**
     * 获取角色的权限列表
     *
     * @param id
     * @return
     */
    override fun getPermissions(id: Int): List<Permission> {
        val role = get(id) ?: return emptyList()
        return if (role.role == "super-admin") {
            database.permissions.toList()
        } else {
            database.from(RolePermissions)
                .leftJoin(Permissions, on = RolePermissions.permission eq Permissions.id)
                .select(Permissions.columns)
                .where { (RolePermissions.role eq id) and (RolePermissions.deleted eq false) }
                .map { row -> Permissions.createEntity(row) }
        }
    }

    /**
     * 更新角色的权限列表
     *
     * @param id
     * @param permissions
     */
    override fun updatePermissions(id: Int, permissions: List<Int>) {
        TODO("Not yet implemented")
    }

    /**
     * 获取角色的菜单
     *
     * @param id
     * @return
     */
    override fun getMenus(id: Int): List<Menu> {
        val role = get(id) ?: return emptyList()
        return if (role.role == "super-admin") {
            database.menus.filter { it.deleted eq false }.toList()
        } else {
            database.from(RoleMenus)
                .leftJoin(Menus, on = RoleMenus.menu eq Menus.id)
                .select(Menus.columns)
                .where { RoleMenus.role eq id and (RoleMenus.deleted eq false) }
                .map { row -> Menus.createEntity(row) }
        }
    }
}